#!/usr/bin/env python

"""
Mind 2 Music
Copyright (C) 2010  Sytze K. Zeijlmaker

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
"""

# TODO: Live editing view
# TODO: Info (A A# B. . .)

import pygtk
pygtk.require("2.0")
import gtk
import gobject
from gtk import gdk
import threading
import time

class EditView(gtk.DrawingArea):
	def __init__(self,m2m):
		super(EditView,self).__init__()
		
		self.popup=m2m.gui.get_widget("editmenu")
		
		self.scaleX=12
		self.scaleY=8
		self.scrollX=0
		self.scrollY=36
		self.oscrollX=0
		self.oscrollY=36
		self.width=0
		self.height=0
		self.drawing=False
		
		self.oselX=0
		self.oselY=0
		self.oselXX=0
		self.selX=0
		self.selY=0
		self.selXX=-1
		self.Mode=0
		
		self.IN=None
		self.OUT=None
		self.player=None
		
		self.buf=gdk.Pixbuf(gdk.COLORSPACE_RGB,False,8,16,9)
		self.art=gdk.pixbuf_new_from_file("gridsimple.bmp")
		
		self.connect("expose-event", self.expose)
		self.connect("button-press-event", self.button)
		self.connect("button-release-event", self.unbutton)
		
		self.set_flags(gtk.CAN_FOCUS)
		self.set_events(gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK)
	
	def expose(self, widget, event):
		self.drawall()
		return True
	
	def key(self, w, event):
		if event.keyval==32:
			self.TogglePlay()
			return True
		
		ctrl=event.state & gdk.CONTROL_MASK
		shift=event.state & gdk.SHIFT_MASK
		alt=event.state & gdk.MOD1_MASK
		if ctrl or shift or alt:
			return False
		
		if event.keyval==65363:
			self.selX+=1
			self.drawall()
			return True
		if event.keyval==65361:
			self.selX-=1
			self.drawall()
			return True
		if event.keyval==65364:
			self.selY+=1
			self.drawall()
			return True
		if event.keyval==65362:
			self.selY-=1
			self.drawall()
			return True
		
		print "key:",event.keyval
		return False
	
	def Insert(bla,bloe,self):
		n=(self.scrollX+self.selX,self.scrollY-self.selY,1)
		self.IN.l.append(n)
		self.oselY=-1
		self.drawall()
		return True
	
	def Duplicate(bla,bloe,self):
		N=None
		for n in self.IN.l:
			if -self.selY+self.scrollY==n[1]:
				if self.selX+self.scrollX>=n[0] and n[0]+n[2]>self.selX+self.scrollX:
					N=n
		
		if N!=None:
			self.IN.l.append(N)
			self.draw_area(self.buf,
				N[0]-self.scrollX,-N[1]+self.scrollY,
				N[0]+N[2]-self.scrollX+1,-N[1]+self.scrollY+1)
			self.drawall()
			
		return True
	
	def Remove(bla,bloe,self):
		N=None
		for n in self.IN.l:
			if -self.selY+self.scrollY==n[1]:
				if self.selX+self.scrollX>=n[0] and n[0]+n[2]>self.selX+self.scrollX:
					N=n
		if N!=None:
			self.IN.l.remove(N)
			self.draw_area(self.buf,
				N[0]-self.scrollX,-N[1]+self.scrollY,
				N[0]+N[2]-self.scrollX+1,-N[1]+self.scrollY+1)
			self.drawall()
			
		return True
	
	def EditEvent(bla,bloe,self,mx,my,s):
		self.EditNote(mx,my,s)
		return False
	
	def MoveEvent(bla,bloe,self,x,y):
		self.selX+=x
		self.selY+=y
		self.drawall()
		return False
	
	def NavEvent(bla,bloe,self,x,y):
		self.selX+=x
		self.selY-=y
		self.scrollX+=x
		self.scrollY+=y
		self.drawall()
		return False
	
	def EditNote(self,mx,my,s):
		n=self.IN.Get(self.selX+self.scrollX,-self.selY+self.scrollY)
		if n==None:
			return
		
		if n[2]<2 and s<0:
			s=0
			
		n2=(n[0]+mx,n[1]+my,n[2]+s)
		
		x1=n[0]-self.scrollX
		y1=-n[1]+self.scrollY
		s1=n[2]
		x2=n2[0]-self.scrollX
		y2=-n2[1]+self.scrollY
		s2=n2[2]
		
		self.IN.Change(n,n2)
		
		if my!=0: #Just draw the whole note...
			self.draw_area(self.buf,x1,y1,x1+s1,y1+1)
			self.draw_area(self.buf,x2,y2,x2+s2,y2+1)
		else: #Draw parts
			if mx>0:
				self.draw_area(self.buf,x1,y1,x2,y2+1)
				self.draw_area(self.buf,x1+s1,y1,x2+s1,y2+1)
			elif mx<0:
				self.draw_area(self.buf,x2,y2,x1,y1+1)
				self.draw_area(self.buf,x2+s1,y2,x1+s1,y1+1)
			if s>0:
				self.draw_area(self.buf,x2+s1,y2,x2+s2,y2+1)
			elif s<0:
				self.draw_area(self.buf,x2+s2,y2,x2+s1,y2+1)
		
		self.selX+=mx
		self.selY-=my
		self.drawall()
		
	
	def SetMode(bla,bloe,self,wat):
		if wat==0:
			self.window.set_cursor(None)
		if wat==1:
			self.window.set_cursor(gdk.Cursor(gdk.PENCIL))
		if wat==2:
			self.window.set_cursor(gdk.Cursor(gdk.TARGET))
		self.Mode=wat
		#self.mu.update_status()
	
	def CtrlC(bla,bloe,self):
		""
	
	def CtrlV(bla,bloe,self):
		""
	
	def CtrlX(bla,bloe,self):
		""
	
	def button(self, w, event):
		x=event.x/self.scaleX
		y=event.y/self.scaleY
		self.selX=int(x)
		self.selY=int(y)
		self.drawall()
		if event.button==3:
			self.popup.popup(None,None,None,event.button,event.time)
		if event.button==1:
			if self.Mode==1 or event.type==gdk._2BUTTON_PRESS:
				self.Insert(None,self)
			if self.Mode==2:
				self.Remove(None,self)
		return True
	
	def unbutton(self, w, event):
		if event.button==1 and (self.Mode==1 or self.Mode==0):
			N=None
			for n in self.IN.l:
				if -self.selY+self.scrollY==n[1]:
					if self.selX+self.scrollX>=n[0] and n[0]+n[2]>self.selX+self.scrollX:
						N=n
			if N!=None:
				x=int(event.x/self.scaleX)
				y=int(event.y/self.scaleY)
				#DRAGGING
				if N[0]+N[2]-1==self.selX+self.scrollX and abs(x-self.selX)>abs(y-self.selY):
					self.EditNote(0,0,x-self.selX)
				else:
					self.EditNote(x-self.selX,-(y-self.selY),0)
				self.selX=x
				self.selY=y
				self.drawall()	
			
		return True
		
	def drawall(self):
		if self.drawing==True:
			return
		
		self.selXX=-1
		if self.player!=None:
			if self.player.abort==False:
				self.selXX=self.player.pos-self.scrollX			
		
		self.drawing=True
		
		nwidth=self.allocation.width/self.scaleX
		nheight=self.allocation.height/self.scaleY
		if nwidth!=self.width or nheight!=self.height:#Resize
			npb=gdk.Pixbuf(gdk.COLORSPACE_RGB,False,8,nwidth*self.scaleX+1,nheight*self.scaleY+1)
			
			swidth=(nwidth*self.scaleX,self.width*self.scaleX)[nwidth>self.width]
			sheight=(nheight*self.scaleY,self.height*self.scaleY)[nheight>self.height]
			
			self.buf.copy_area(0,0,swidth,sheight,npb,0,0)
			
			if nwidth>self.width:
				self.draw_area(npb, self.width, 0, nwidth, self.height)
			if nheight>self.height:
				self.draw_area(npb, 0, self.height, self.width, nheight)
			if nwidth>self.width and nheight>self.height:
				self.draw_area(npb, self.width, self.height, nwidth, nheight)
			
			self.buf=npb
			
			self.width=nwidth
			self.height=nheight
			self.oscrollX==self.scrollX
			self.oscrollY=self.scrollY
			self.oselX=self.selX
			self.oselY=self.selY
			self.oselXX=self.selXX
		
		if self.oscrollX!=self.scrollX or self.oscrollY!=self.scrollY:#Scroll
			sx=(self.scrollX-self.oscrollX)*self.scaleX
			sy=-(self.scrollY-self.oscrollY)*self.scaleY
			sw=self.width*self.scaleX+sx
			sh=self.height*self.scaleY+sy
			if sx<0:
				sx=0
			if sy<0:
				sy=0
			if sw>self.width*self.scaleX:
				sw=self.width*self.scaleX
			if sh>self.height*self.scaleY:
				sh=self.height*self.scaleY
			w=sw-sx
			h=sh-sy
			dx=(self.oscrollX-self.scrollX)*self.scaleX
			dy=-(self.oscrollY-self.scrollY)*self.scaleY
			if dx<0:
				dx=0
			if dy<0:
				dy=0
			
			# I have to make a temporary pixbuf, because it cant'
			# copy to itself
			npb=gdk.Pixbuf(gdk.COLORSPACE_RGB,False,8,nwidth*self.scaleX+1,nheight*self.scaleY+1)
			self.buf.copy_area(sx,sy,w,h,npb,dx,dy)
			self.buf=npb
			
			x=self.scrollX-self.oscrollX
			y=-(self.scrollY-self.oscrollY)
			if x>0:
				self.draw_area(self.buf,self.width-x,0,self.width,self.height)
			if x<0:
				self.draw_area(self.buf,0,0,-x,self.height)
			if y>0:
				self.draw_area(self.buf,0,self.height-y,self.width,self.height)
			if y<0:
				self.draw_area(self.buf,0,0,self.width,-y)
			
			self.selX=self.selX-self.scrollX+self.oscrollX
			self.selY=self.selY+self.scrollY-self.oscrollY
			self.oselX=self.oselX-self.scrollX+self.oscrollX
			self.oselY=self.oselY+self.scrollY-self.oscrollY
			self.oscrollX=self.scrollX
			self.oscrollY=self.scrollY
		
		if self.oselX!=self.selX or self.oselY!=self.selY:
			self.draw_area(self.buf,self.oselX,self.oselY,self.oselX+1,self.oselY+1)
			self.draw_area(self.buf,self.selX,self.selY,self.selX+1,self.selY+1)
			self.oselX=self.selX
			self.oselY=self.selY
		
		if self.oselXX!=self.selXX:
			if self.oselXX>=0 and self.oselXX<self.width:
				self.draw_area(self.buf,self.oselXX,0,self.oselXX+1,self.height)
			if self.selXX>=0 and self.selXX<self.width:
				self.draw_area(self.buf,self.selXX,0,self.selXX+1,self.height)
			self.oselXX=self.selXX
		
		self.window.draw_pixbuf(self.get_style().black_gc, self.buf, 0,0,0,0)
		
		self.drawing=False
		return False;
	
	def draw_area(self, pb, x1, y1, x2, y2):
		for x in range(x1,x2):
			for y in range(y1,y2):
				Id=0
				if (x+self.scrollX)%8<4:
					Id=1
					
				if self.IN!=None:
					for n in self.IN.l:
						if -y+self.scrollY==n[1]:
							if x+self.scrollX>=n[0] and n[0]+n[2]>x+self.scrollX:
								if Id==2 or Id==3:
									Id=3
								else:
									Id=2
				
				if (x==self.selX and y==self.selY) or x==self.selXX:
					Id+=4
				
				self.draw_block(pb, x*self.scaleX, y*self.scaleY, self.scaleX, self.scaleY, Id)
	
	def draw_block(self, pb, x, y, w, h, Id):
		if x<0:
			return
		if y<0:
			return
		
		
		x1=(Id%4)*32
		y1=(Id/4)*32
		
		halfw=w/2
		halfh=h/2
		midx=x+w-halfw
		midy=y+h-halfh
		
		self.art.copy_area(x1,y1,halfw,halfh,pb,x,y)
		self.art.copy_area(x1+32-halfw,y1,halfw,halfh,pb,midx,y)
		self.art.copy_area(x1+32-halfw,y1+32-halfh,halfw,halfh,pb,midx,midy)
		self.art.copy_area(x1,y1+32-halfh,halfw,halfh,pb,x,midy)
	
	def TogglePlay(self):
		if self.player==None or self.player.abort==True:
			self.player=Composition.Player(self.IN,0,self)
			self.player.start()
		else:
			self.player.abort=True
			self.player=None

		
